//
// Created by Administrator on 25-7-19.
//

#include "sram_ex.h"
SRAM_HandleTypeDef g_sram_ex_handle;

/**
 * @brief 初始化外部SRAM
 * 
 * 该函数初始化FSMC和相关GPIO，设置SRAM的时序参数
 * 
 * @return 无
 */
void sram_ex_init(void)
{
    GPIO_InitTypeDef gpio_initstruct={0};
    FSMC_NORSRAM_TimingTypeDef fsmc_rw_timing={0};

    // 使能SRAM控制引脚的GPIO时钟
    SRAM_CS_GPIO_CLK_ENABLE();
    SRAM_WR_GPIO_CLK_ENABLE();
    SRAM_RD_GPIO_CLK_ENABLE();

    // 使能FSMC和相关GPIO端口的时钟
    __HAL_RCC_FSMC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE();

    // 配置SRAM的片选引脚
    gpio_initstruct.Pin=SRAM_CS_GPIO_PIN;
    gpio_initstruct.Mode=GPIO_MODE_AF_PP;
    gpio_initstruct.Pull=GPIO_PULLUP;
    gpio_initstruct.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_initstruct.Alternate=GPIO_AF12_FSMC;
    HAL_GPIO_Init(SRAM_CS_GPIO_PORT,&gpio_initstruct);

    // 配置SRAM的读使能引脚
    gpio_initstruct.Pin=SRAM_RD_GPIO_PIN;
    HAL_GPIO_Init(SRAM_RD_GPIO_PORT,&gpio_initstruct);

    // 配置SRAM的写使能引脚
    gpio_initstruct.Pin=SRAM_WR_GPIO_PIN;
    HAL_GPIO_Init(SRAM_WR_GPIO_PORT,&gpio_initstruct);

    // 配置GPIOD的FSMC相关引脚（PD0,1,4,5,8~15）
    gpio_initstruct.Pin=\
    GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 | GPIO_PIN_9 \
    | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    gpio_initstruct.Mode=GPIO_MODE_AF_PP;
    gpio_initstruct.Pull=GPIO_PULLUP;
    HAL_GPIO_Init(GPIOD,&gpio_initstruct);

    // 配置GPIOE的FSMC相关引脚（PE0,1,7-15）
    gpio_initstruct.Pin=\
    GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11\
    |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    HAL_GPIO_Init(GPIOE,&gpio_initstruct);

    // 配置GPIOF的FSMC相关引脚（PF0-5,12-15）
    gpio_initstruct.Pin=\
    GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_12\
    |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
    HAL_GPIO_Init(GPIOF,&gpio_initstruct);

    // 配置GPIOG的FSMC相关引脚（PG0-5,10）
    gpio_initstruct.Pin=\
    GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_10;
    HAL_GPIO_Init(GPIOG,&gpio_initstruct);

    // 设置FSMC SRAM设备的基本配置
    g_sram_ex_handle.Instance=FSMC_NORSRAM_DEVICE;
    g_sram_ex_handle.Extended=FSMC_NORSRAM_EXTENDED_DEVICE;
    g_sram_ex_handle.Init.NSBank=FSMC_NORSRAM_BANK3;
    g_sram_ex_handle.Init.DataAddressMux=FSMC_DATA_ADDRESS_MUX_DISABLE;
    g_sram_ex_handle.Init.MemoryType=FSMC_MEMORY_TYPE_SRAM;
    g_sram_ex_handle.Init.MemoryDataWidth=FSMC_NORSRAM_MEM_BUS_WIDTH_16;
    g_sram_ex_handle.Init.BurstAccessMode=FSMC_BURST_ACCESS_MODE_DISABLE;
    g_sram_ex_handle.Init.WaitSignalPolarity=FSMC_WAIT_SIGNAL_POLARITY_LOW;
    g_sram_ex_handle.Init.WaitSignalActive=FSMC_WAIT_TIMING_BEFORE_WS;
    g_sram_ex_handle.Init.WriteOperation=FSMC_WRITE_OPERATION_ENABLE;
    g_sram_ex_handle.Init.WaitSignal=FSMC_WAIT_SIGNAL_DISABLE;
    g_sram_ex_handle.Init.ExtendedMode=FSMC_EXTENDED_MODE_DISABLE;
    g_sram_ex_handle.Init.AsynchronousWait=FSMC_ASYNCHRONOUS_WAIT_DISABLE;
    g_sram_ex_handle.Init.WriteBurst=FSMC_WRITE_BURST_DISABLE;

    // 设置FSMC的读写时序参数
    fsmc_rw_timing.AddressSetupTime=0x00;
    fsmc_rw_timing.AddressHoldTime=0x00;
    fsmc_rw_timing.DataSetupTime=0x08;
    fsmc_rw_timing.BusTurnAroundDuration=0x00;
    fsmc_rw_timing.AccessMode=FSMC_ACCESS_MODE_A;
    HAL_SRAM_Init(&g_sram_ex_handle,&fsmc_rw_timing,&fsmc_rw_timing);
}

/**
 * @brief 向外部SRAM写入数据
 * 
 * @param pbuf 指向要写入数据的指针
 * @param addr 要写入的地址（相对于SRAM基地址）
 * @param datalen 要写入的数据长度（字节）
 * 
 * @return 无
 */
void sram_ex_write(uint8_t *pbuf, uint32_t addr, uint32_t datalen)
{
    for (;datalen!=0;datalen--)
    {
        *(volatile uint8_t *)(SRAM_BASE_ADDR+addr)=*pbuf;
        addr++;
        pbuf++;
    }
}

/**
 * @brief 从外部SRAM读取数据
 * 
 * @param pbuf 指向存储读取数据的缓冲区的指针
 * @param addr 要读取的地址（相对于SRAM基地址）
 * @param datalen 要读取的数据长度（字节）
 * 
 * @return 无
 */
void sram_ex_read(uint8_t *pbuf,uint32_t addr, uint32_t datalen)
{
    for (uint32_t i=0;i<datalen;i++)
    {
        pbuf[i]=*(volatile uint8_t *)(SRAM_BASE_ADDR+addr);
        addr++;
    }
}

